import fcntl
import inspect
import logging
import logging.handlers
import os
import threading
import time
from pathlib import Path
from typing import List

from app.config.settings import settings

APP_NAME = settings.get('app.name', 'fw_paddleocr_web')
is_dev_tools = settings.get('app.dev', False)
# 模块级控制变量
_setup_completed = False
_setup_lock = threading.Lock()


class LoggerManager:
    """日志管理器单例类"""
    _instance = None
    _initialized = False
    _instance_lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._instance_lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        """初始化日志管理器"""
        if not hasattr(self, '_log_stats'):
            # 初始化日志统计字典
            self._log_stats = {
                'DEBUG': 0,
                'INFO': 0,
                'WARNING': 0,
                'ERROR': 0,
                'CRITICAL': 0
            }

    def setup_logging(self):
        """设置日志配置"""
        # 线程安全检查
        with self._instance_lock:
            if self._initialized:
                return

            self._initialize_log_files()
            self._setup_root_logger()
            self._setup_system_logger()
            self._setup_app_logger()
            self._setup_special_handlers()
            self._setup_third_party_loggers()

            self._initialized = True

    def get_log_stats(self):
        return self._log_stats.copy()

    def _initialize_log_files(self):
        """初始化日志文件"""
        # 获取日志配置
        self.log_level = getattr(logging, settings.get('logging.level', 'INFO'))
        self.app_log_file = settings.get('logging.app_file_path')
        self.system_log_file = settings.get('logging.system_file_path')
        self.error_log_file = settings.get('logging.error_file_path')
        self.console_log_file = settings.get('logging.all_file_path')

        # 确保日志文件存在
        app_log_path = Path(self.app_log_file)
        system_log_path = Path(self.system_log_file)
        error_log_path = Path(self.error_log_file)
        console_log_path = Path(self.console_log_file)

        # 检查并创建日志文件的父目录
        for log_path in [app_log_path, system_log_path, error_log_path, console_log_path]:
            if not log_path.parent.exists():
                log_path.parent.mkdir(parents=True, exist_ok=True)

        # 检查并创建日志文件
        for log_path in [app_log_path, system_log_path, error_log_path, console_log_path]:
            if not log_path.exists():
                log_path.touch()

    def _setup_root_logger(self):
        """设置根日志器"""
        # ===== 根日志器 =====
        self.root_logger = logging.getLogger()
        self.root_logger.setLevel(logging.DEBUG)  # 根日志器必须为 DEBUG 才能捕获所有日志
        self.root_logger.handlers.clear()

    def _setup_system_logger(self):
        """设置系统日志记录器"""
        # ===== 1. 系统日志处理器 =====
        # 系统日志处理器记录 DEBUG 级别及以上日志
        self.system_handler = self._create_handler(self.system_log_file, logging.DEBUG, 'system_handler')
        self.system_logger = logging.getLogger('system')
        self.system_logger.setLevel(logging.DEBUG)
        self.system_logger.handlers.clear()
        self.system_logger.addHandler(self.system_handler)
        
        # 在开发模式下，也为system logger添加控制台流处理器
        if is_dev_tools and hasattr(self, 'console_stream_handler'):
            self.system_logger.addHandler(self.console_stream_handler)

    def _setup_app_logger(self):
        """设置获取modules目录日志记录器"""
        # ===== 2. 应用日志处理器 =====
        # 应用日志处理器记录全局设置的日志级别及以上日志
        self.app_handler = self._create_handler(self.app_log_file, self.log_level, 'app_handler')
        self.app_logger = logging.getLogger('app')
        self.app_logger.setLevel(self.log_level)
        self.app_logger.handlers.clear()
        self.app_logger.addHandler(self.app_handler)
        
        # 在开发模式下，也为app logger添加控制台流处理器
        if is_dev_tools and hasattr(self, 'console_stream_handler'):
            self.app_logger.addHandler(self.console_stream_handler)

    def _setup_special_handlers(self):
        """设置特殊用途的日志处理器"""
        # ===== 3. 统一日志处理器 =====  统一日志处理器记录所有级别的日志到文件
        self.all_log_handler = self._create_handler(self.console_log_file, logging.DEBUG, 'all_log_handler')

        # 添加 StreamHandler 到控制台（仅在开发模式下）
        if is_dev_tools:
            self.console_stream_handler = logging.StreamHandler()
            self.console_stream_handler.setLevel(logging.DEBUG)
            formatter = logging.Formatter(settings.get('logging.format'))
            self.console_stream_handler.setFormatter(formatter)
            self.console_stream_handler.name = 'console_stream_handler'

        # 错误日志处理器记录 ERROR 级别及以上日志
        self.error_handler = self._create_handler(self.error_log_file, logging.ERROR, 'error_handler')
        # 添加级别过滤器确保只记录ERROR及以上级别的日志
        self.error_handler.addFilter(LevelRangeFilter('ERROR', 'CRITICAL'))

        # ===== 最后：为根日志器添加处理器 ===== 根日志器添加错误处理器、统一日志处理器
        self.root_logger.addHandler(self.error_handler)
        self.root_logger.addHandler(self.all_log_handler)
        
        # 在开发模式下，也添加控制台流处理器
        if is_dev_tools:
            self.root_logger.addHandler(self.console_stream_handler)

    def _setup_third_party_loggers(self):
        # 处理第三方库日志
        third_party_cfg = settings.get('logging.third_party', {})
        for logger_name, cfg in third_party_cfg.items():
            # 检查是否启用该库的日志记录 (默认为True以保持向后兼容)
            enabled = cfg.get('enabled', True)
            if not enabled:
                # 如果禁用，则将该库的日志级别设置为CRITICAL以阻止日志输出
                disabled_logger = logging.getLogger(logger_name)
                disabled_logger.setLevel(logging.CRITICAL)
                disabled_logger.handlers.clear()
                print(f"[DEBUG] 被阻止第三方库日志记录器: {logger_name}，不会输出任何日志到文件中。")
                continue

            third_party_logger = logging.getLogger(logger_name)
            third_party_logger.propagate = False
            # 允许接收所有级别的日志
            third_party_logger.setLevel(logging.DEBUG)
            # 解析配置文件中设置的第三方库设置的日志级别
            level = getattr(logging, cfg.get('level').upper())
            third_party_logger.setLevel(level)

            target = cfg.get('target')
            filters_cfg = cfg.get('filters', [])

            # ===== 处理 target: 字符串或字典 =====
            handlers_to_add = []

            if isinstance(target, dict):
                # 按级别路由
                for level_key, dest in target.items():
                    level_val = getattr(logging, level_key.upper())
                    if isinstance(dest, str):
                        # 直接文件路径
                        h = self._create_handler(dest, level_val)
                    elif isinstance(dest, dict):
                        # 包含 filters 的复杂配置
                        file_path = dest['file']
                        h = self._create_handler(file_path, level_val)
                        # 添加过滤器
                        for f_cfg in dest.get('filters', []):
                            f_type = f_cfg['type']
                            if f_type == 'level_range':
                                min_ = f_cfg.get('min_level', 'DEBUG')
                                max_ = f_cfg.get('max_level', 'CRITICAL')
                                h.addFilter(LevelRangeFilter(min_, max_))
                            elif f_type == 'keyword':
                                inc = f_cfg.get('include_keywords', [])
                                exc = f_cfg.get('exclude_keywords', [])
                                h.addFilter(KeywordFilter(include_keywords=inc, exclude_keywords=exc))
                    else:
                        continue
                    print(f"[DEBUG] 为第三方库日志记录器: {logger_name}，添加日志处理器: {file_path}")
                    h.addFilter(LevelRangeFilter(level_key, level_key))  # 确保只处理该级别
                    handlers_to_add.append(h)
            elif target == "separate" and 'file' in cfg:
                h = self._create_handler(cfg['file'], level)
                # 添加 filters
                for f_cfg in filters_cfg:
                    if f_cfg['type'] == 'level_range':
                        min_ = f_cfg.get('min_level', 'DEBUG')
                        max_ = f_cfg.get('max_level', 'CRITICAL')
                        h.addFilter(LevelRangeFilter(min_, max_))
                    elif f_cfg['type'] == 'keyword':
                        inc = f_cfg.get('include_keywords', [])
                        exc = f_cfg.get('exclude_keywords', [])
                        h.addFilter(KeywordFilter(include_keywords=inc, exclude_keywords=exc))
                handlers_to_add.append(h)

            # 清除旧处理器
            third_party_logger.handlers.clear()

            # 添加新处理器
            for h in handlers_to_add:
                third_party_logger.addHandler(h)
                # print(f"[DEBUG] 已初始化第三方库日志记录器: {logger_name}，会输出日志到 {third_party_logger} 文件中。")

            # 确保第三方库日志总是记录到统一日志处理器
            third_party_logger.addHandler(self.all_log_handler)
            
            # 在开发模式下，也添加控制台流处理器
            if is_dev_tools and hasattr(self, 'console_stream_handler'):
                third_party_logger.addHandler(self.console_stream_handler)

    def _create_handler(self, filename: str, handler_level: int, handler_name: str = None):
        """
        创建文件处理器的通用函数

        Args:
            filename: 日志文件路径
            handler_level: 处理器日志级别
            handler_name: 处理器名称

        Returns:
            logging.handlers.RotatingFileHandler: 配置好的文件处理器
        """
        # 获取日志配置
        base_max_bytes = settings.get('logging.max_bytes')
        base_backup_count = settings.get('logging.backup_count')
        _handler = logging.handlers.RotatingFileHandler(
            filename, maxBytes=base_max_bytes, backupCount=base_backup_count, encoding='utf-8'
        )
        _handler.setLevel(handler_level)

        # 使用默认的日志格式
        formatter = logging.Formatter(settings.get('logging.format'))
        _handler.setFormatter(formatter)

        if handler_name:
            _handler.name = handler_name
        return _handler


# 创建单例实例
_logger_manager = LoggerManager()


def setup_logging():
    """设置日志配置(单例模式)"""
    global _setup_completed

    # 添加调试信息
    current_thread = threading.current_thread().name
    process_id = os.getpid()
    timestamp = time.time()

    # 将timestamp转换为[年-月-日 小时:分钟:秒.毫秒]格式
    formatted_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
    milliseconds = f"{(timestamp % 1 * 1000):03.0f}"
    formatted_timestamp = f"{formatted_time}.{milliseconds}"
    
    print(f"[DEBUG] setup_logging 被调用 - 进程ID: {process_id}, 线程: {current_thread}, 时间: {formatted_timestamp}")

    with _setup_lock:
        if _setup_completed:
            print(f"[DEBUG] setup_logging 已在进程 {process_id} 中完成，跳过执行")
            return

        # 使用文件锁防止多进程重复初始化
        lock_file_path = Path("../logs/logger_init.lock")
        lock_file_path.parent.mkdir(parents=True, exist_ok=True)

        try:
            with open(lock_file_path, 'w') as lock_file:
                fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
                # print(f"[DEBUG] 在进程 {process_id} 中开始执行日志配置")
                _logger_manager.setup_logging()
                _setup_completed = True
                # print(f"[DEBUG] 在进程 {process_id} 中日志配置完成")
                # 注意：这里不释放文件锁，让它保持到进程结束
        except IOError:
            # 另一个进程正在进行初始化或已完成初始化
            print(f"[DEBUG] 进程 {process_id} 检测到其他进程正在进行初始化，跳过执行")
            _setup_completed = True  # 标记为已完成，避免后续重复尝试
            return


def get_logger(name=None):
    """获取日志记录器"""

    # 检查是否为调试模式
    if settings.get('app.is_get_logger_name_console_output', False):
        current_thread = threading.current_thread()
        current_thread.name = f'{current_thread.name} - {name}'
        frame = inspect.currentframe().f_back
        print(f"[DEBUG] get_logger 被调用 - 名称: {name}")
    # 如果没有提供名称，则尝试自动推断
    if name is None:
        # 获取调用者的模块名
        frame = inspect.currentframe().f_back
        module_name = frame.f_globals['__name__']
        name = module_name

    if name.startswith('system.'):
        return logging.getLogger(name)
    elif name.startswith('app.'):
        return logging.getLogger(name)
    else:
        # 默认分配到业务日志
        return logging.getLogger(name)


# ===== 自定义过滤器 =====
class LevelRangeFilter(logging.Filter):
    """根据日志级别范围过滤"""

    def __init__(self, min_level: str = "DEBUG", max_level: str = "CRITICAL"):
        super().__init__()
        self.min_level = getattr(logging, min_level.upper())
        self.max_level = getattr(logging, max_level.upper())

    def filter(self, record: logging.LogRecord) -> bool:
        return self.min_level <= record.levelno <= self.max_level


class KeywordFilter(logging.Filter):
    """关键词过滤器：支持包含/排除"""

    def __init__(self, include_keywords: List[str] = None, exclude_keywords: List[str] = None):
        super().__init__()
        self.include_keywords = [k.lower() for k in (include_keywords or [])]
        self.exclude_keywords = [k.lower() for k in (exclude_keywords or [])]

    def filter(self, record: logging.LogRecord) -> bool:
        msg = record.getMessage().lower()
        # 排除关键词
        if self.exclude_keywords and any(k in msg for k in self.exclude_keywords):
            return False
        # 包含关键词（如果设置了）
        if self.include_keywords and not any(k in msg for k in self.include_keywords):
            return False
        return True
